﻿using System;
using System.Data.Objects;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;

namespace DataProject
{
    public static class IQueryableExtensions
    {
        public static IQueryable<TEntity> Paginate<TEntity, S>(this IQueryable<TEntity> queryable, Expression<Func<TEntity, S>> orderBy, int pageIndex, int pageCount, bool ascending)
            where TEntity : class
        {
            ObjectQuery<TEntity> query = queryable as ObjectQuery<TEntity>;

            if (query != null)
            {
                string orderPath = AnalyzeExpressionPath(orderBy);

                return query.Skip(string.Format(CultureInfo.InvariantCulture, "it.{0} {1}", orderPath, (ascending) ? "asc" : "desc"), "@skip", new ObjectParameter("skip", (pageIndex) * pageCount))
                            .Top("@limit", new ObjectParameter("limit", pageCount));

            }

            return queryable.OrderBy(orderBy).Skip((pageIndex * pageCount)).Take(pageCount);
        }

        #region Private Methods

        static string AnalyzeExpressionPath<TEntity, S>(Expression<Func<TEntity, S>> expression)
            where TEntity : class
        {
            if (expression == null)
            {
                throw new ArgumentNullException(Resources.Messages.InvalidExpressionPath);
            }

            MemberExpression body = expression.Body as MemberExpression;
            if (
                (
                    (body == null)
                    ||
                    !body.Member.DeclaringType.IsAssignableFrom(typeof(TEntity))
                )
                ||
                (body.Expression.NodeType != ExpressionType.Parameter)
                )
            {
                throw new ArgumentException(Resources.Messages.InvalidExpressionPath);
            }

            return body.Member.Name;
        }

        #endregion
    }
}
